package ru.ifmo.genetics.automaton.synchronizeable.fitness;

import org.uncommons.watchmaker.framework.FitnessEvaluator;
import ru.ifmo.automaton.Automaton;
import ru.ifmo.common.Source;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author avhaliullin
 */
public class StandartFitness implements FitnessEvaluator<String> {
    private final Source<Automaton<Character, String>> automatonSource;

    public StandartFitness(Source<Automaton<Character, String>> automatonSource) {
        this.automatonSource = automatonSource;
    }

    private static String handleWord(Automaton<Character, String> automaton, String word) {
        Character[] wordChars = new Character[word.length()];
        for (int i = 0; i < word.length(); i++) {
            wordChars[i] = word.charAt(i);
        }
        return automaton.step(wordChars);
    }

    public static int df(Automaton<Character, String> automaton, String candidate) {
        Set<String> states = new HashSet<String>();
        for (String state : automaton) {
            automaton.goToState(state);
            states.add(handleWord(automaton, candidate));
        }
        return automaton.getStatesCount() - states.size();
    }

    public double getFitness(String candidate, List<? extends String> population) {
        if (candidate.length() == 0) {
            return 0;
        }
        return Math.pow(df(automatonSource.create(), candidate), 4) / Math.pow(candidate.length(), 0.25);
    }

    public boolean isNatural() {
        return true;
    }

}
